/*
 * IBP - Technology architecture for real-time transaction
 * author	: calvin
 * email	: calvinwilliams@163.com
 *
 * Licensed under the LGPL v2.1, see the file LICENSE in base directory.
 */

#include "ibtm_in.h"

struct DynamicStruct *DSAllocStruct( char *struct_name )
{
	struct DynamicStruct	*p_struct = NULL ;
	
	p_struct = (struct DynamicStruct *)malloc( sizeof(struct DynamicStruct) ) ;
	if( p_struct == NULL )
		return NULL;
	memset( p_struct , 0x00 , sizeof(struct DynamicStruct) );
	
	p_struct->struct_name = strdup( struct_name ) ;
	if( p_struct->struct_name == NULL )
		return NULL;
	
	return p_struct;
}

void DSDestroyStruct( struct DynamicStruct *p_struct )
{
	if( p_struct )
	{
		if( p_struct->struct_name )
			free( p_struct->struct_name );
		
		DestroyDynamicStructFieldTree( p_struct );
		
		free( p_struct );
	}
	
	return;
}

int DSGetLastSourceLine( struct DynamicStruct *p_struct )
{
	return p_struct->last_source_line;
}

char *DSGetFieldName( struct DynamicStruct *p_struct )
{
	return p_struct->last_field_name;
}

int DSGetLastError( struct DynamicStruct *p_struct )
{
	return p_struct->error;
}

static struct DynamicStructField *_DSAllocField( char *field_name , char *field_type , int field_value_size )
{
	struct DynamicStructField	*p_field = NULL ;
	
	p_field = (struct DynamicStructField *)malloc( sizeof(struct DynamicStructField) ) ;
	if( p_field == NULL )
		return NULL;
	
	p_field->field_name = strdup( field_name ) ;
	if( p_field->field_name == NULL )
	{
		free( p_field );
		return NULL;
	}
	
	p_field->field_type = strdup( field_type ) ;
	if( p_field->field_type == NULL )
	{
		free( p_field->field_name );
		free( p_field );
		return NULL;
	}
	
	p_field->field_value = malloc( field_value_size ) ;
	if( p_field->field_value == NULL )
	{
		free( p_field->field_name );
		free( p_field->field_type );
		free( p_field );
		return NULL;
	}
	
	p_field->field_value_size = field_value_size ;
	
	return p_field;
}

int DSAddField( int __line__ , struct DynamicStruct *p_struct , char *field_type , int field_type_size , char *field_name , ... )
{
	va_list				valist ;
	struct DynamicStructField	*p_field = NULL ;
	int				nret = 0 ;
	
	p_struct->last_source_line = __line__ ;
	p_struct->last_field_name = field_name ;
	p_struct->error = 0 ;
	
	va_start( valist , field_name );
	
	if( STRCMP( field_type , == , "char" ) )
	{
		char		*p_value = NULL ;
		
		p_field = _DSAllocField( field_name , field_type , sizeof(char) ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_value = (char*)(p_field->field_value) ;
		(*p_value) = (char)va_arg( valist , int ) ;
	}
	else if( STRCMP( field_type , == , "short" ) )
	{
		short		*p_value = NULL ;
		
		p_field = _DSAllocField( field_name , field_type , sizeof(short) ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_value = (short*)(p_field->field_value) ;
		(*p_value) = (short)va_arg( valist , int ) ;
	}
	else if( STRCMP( field_type , == , "int" ) )
	{
		short		*p_value = NULL ;
		
		p_field = _DSAllocField( field_name , field_type , sizeof(int) ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_value = (short*)(p_field->field_value) ;
		(*p_value) = va_arg( valist , int ) ;
	}
	else if( STRCMP( field_type , == , "long" ) )
	{
		long		*p_value = NULL ;
		
		p_field = _DSAllocField( field_name , field_type , sizeof(long) ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_value = (long*)(p_field->field_value) ;
		(*p_value) = va_arg( valist , long ) ;
	}
	else if( STRCMP( field_type , == , "float" ) )
	{
		float		*p_value = NULL ;
		
		p_field = _DSAllocField( field_name , field_type , sizeof(float) ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_value = (float*)(p_field->field_value) ;
		(*p_value) = (float)va_arg( valist , double ) ;
	}
	else if( STRCMP( field_type , == , "double" ) )
	{
		double		*p_value = NULL ;
		
		p_field = _DSAllocField( field_name , field_type , sizeof(double) ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_value = (double*)(p_field->field_value) ;
		(*p_value) = va_arg( valist , double ) ;
	}
	else if( STRCMP( field_type , == , "char*" ) )
	{
		char		*p = va_arg( valist , char* ) ;
		int		len = strlen(p) ;
		
		p_field = _DSAllocField( field_name , field_type , len+1 ) ;
		if( p_field == NULL )
			return (p_struct->error=ENOMEM);
		nret = LinkDynamicStructFieldTreeNode( p_struct , p_field ) ;
		if( nret )
			return (p_struct->error=EINVAL);
		p_field->field_value_len = len ;
		strcpy( (char*)(p_field->field_value) , p );
	}
	else
	{
		return (p_struct->error=EINVAL);
	}
	
	va_end( valist );
	
	return 0;
}

int DSSetField( int __line__ , struct DynamicStruct *p_struct , char *field_type , int field_type_size , char *field_name , ... )
{
	va_list				valist ;
	struct DynamicStructField	field ;
	struct DynamicStructField	*p_field = NULL ;
	
	p_struct->last_source_line = __line__ ;
	p_struct->last_field_name = field_name ;
	p_struct->error = 0 ;
	
	va_start( valist , field_name );
	
	memset( & field , 0x00 , sizeof(struct DynamicStructField) );
	field.field_name = field_name ;
	p_field = QueryDynamicStructFieldTreeNode( p_struct , & field ) ;
	if( p_field == NULL )
		return (p_struct->error=EINVAL);
	
	if( STRCMP( field_type , != , p_field->field_type ) )
		return (p_struct->error=EINVAL);
	
	if( STRCMP( field_type , == , "char" ) )
	{
		char		*p_value = NULL ;
		
		p_value = (char*)(p_field->field_value) ;
		(*p_value) = (char)va_arg( valist , int ) ;
	}
	else if( STRCMP( field_type , == , "short" ) )
	{
		short		*p_value = NULL ;
		
		p_value = (short*)(p_field->field_value) ;
		(*p_value) = (short)va_arg( valist , int ) ;
	}
	else if( STRCMP( field_type , == , "int" ) )
	{
		short		*p_value = NULL ;
		
		p_value = (short*)(p_field->field_value) ;
		(*p_value) = va_arg( valist , int ) ;
	}
	else if( STRCMP( field_type , == , "long" ) )
	{
		long		*p_value = NULL ;
		
		p_value = (long*)(p_field->field_value) ;
		(*p_value) = va_arg( valist , long ) ;
	}
	else if( STRCMP( field_type , == , "float" ) )
	{
		float		*p_value = NULL ;
		
		p_value = (float*)(p_field->field_value) ;
		(*p_value) = (float)va_arg( valist , double ) ;
	}
	else if( STRCMP( field_type , == , "double" ) )
	{
		double		*p_value = NULL ;
		
		p_value = (double*)(p_field->field_value) ;
		(*p_value) = va_arg( valist , double ) ;
	}
	else if( STRCMP( field_type , == , "char*" ) )
	{
		char	*p = va_arg( valist , char* ) ;
		int	len = strlen(p) ;
		int	size = len+1 ;
		
		if( size > p_field->field_value_size )
		{
			char	*tmp = (char*)realloc( p_field->field_value , size ) ;
			if( tmp == NULL )
				return (p_struct->error=ENOMEM);
			p_field->field_value_size = size ;
			p_field->field_value = tmp ;
		}
		p_field->field_value_len = len ;
		strcpy( (char*)(p_field->field_value) , p );
	}
	else
	{
		return (p_struct->error=EINVAL);
	}
	
	va_end( valist );
	
	return 0;
}

int DSGetField( int __line__ , struct DynamicStruct *p_struct , char *field_type , int field_type_size , char *field_name , ... )
{
	va_list				valist ;
	struct DynamicStructField	field ;
	struct DynamicStructField	*p_field = NULL ;
	
	p_struct->last_source_line = __line__ ;
	p_struct->last_field_name = field_name ;
	p_struct->error = 0 ;
	
	va_start( valist , field_name );
	
	memset( & field , 0x00 , sizeof(struct DynamicStructField) );
	field.field_name = field_name ;
	p_field = QueryDynamicStructFieldTreeNode( p_struct , & field ) ;
	if( p_field == NULL )
		return (p_struct->error=EINVAL);
	
	if( STRCMP( field_type , != , p_field->field_type ) )
		return (p_struct->error=EINVAL);
	
	if( STRCMP( field_type , == , "char" ) )
	{
		char		*p_value = NULL ;
		
		p_value = (char*)(p_field->field_value) ;
		*(va_arg(valist,char*)) = (*p_value) ;
	}
	else if( STRCMP( field_type , == , "short" ) )
	{
		short		*p_value = NULL ;
		
		p_value = (short*)(p_field->field_value) ;
		*(va_arg(valist,short*)) = (*p_value) ;
	}
	else if( STRCMP( field_type , == , "int" ) )
	{
		short		*p_value = NULL ;
		
		p_value = (short*)(p_field->field_value) ;
		*(va_arg(valist,int*)) = (*p_value) ;
	}
	else if( STRCMP( field_type , == , "long" ) )
	{
		long		*p_value = NULL ;
		
		p_value = (long*)(p_field->field_value) ;
		*(va_arg(valist,long*)) = (*p_value) ;
	}
	else if( STRCMP( field_type , == , "float" ) )
	{
		float		*p_value = NULL ;
		
		p_value = (float*)(p_field->field_value) ;
		*(va_arg(valist,float*)) = (*p_value) ;
	}
	else if( STRCMP( field_type , == , "double" ) )
	{
		double		*p_value = NULL ;
		
		p_value = (double*)(p_field->field_value) ;
		*(va_arg(valist,double*)) = (*p_value) ;
	}
	else if( STRCMP( field_type , == , "char*" ) )
	{
		char	*field_value_string = va_arg( valist , char* ) ;
		int	new_field_value_size = va_arg( valist , ssize_t ) ;
		
		if( new_field_value_size-1 < p_field->field_value_len )
			return (p_struct->error=EINVAL);
		strcpy( field_value_string , (char*)(p_field->field_value) );
	}
	else
	{
		return (p_struct->error=EINVAL);
	}
	
	va_end( valist );
	
	return 0;
}

